package edu.stanford.prpl.dynUI.templates;

import java.io.*;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.net.URLDecoder;
import java.net.URLEncoder;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import edu.stanford.prpl.dynUI.UIEngine;
import edu.stanford.prpl.dynUI.UIEngine.devicePlatform;


public class DynNaviListPageUITemplate extends UITemplate
{
    private String listPageTitleFormat = null;
	private Map<String,DynNaviListUITemplate> sublistTemplates
	= new HashMap<String,DynNaviListUITemplate>();

	
	public DynNaviListPageUITemplate(devicePlatform dP)
	{
		super("dynUI:listPage", dP);
		sublistTemplates.put("*", new DynNaviListUITemplate("*", this.selectedPlatform));
	}


	public void parseTemplate(XmlPullParser xpp) throws Exception
	{
	    // Assumes to be at the starting tag for the current UI template
		// <dynUI:listPage dataObjectName="...">
		xpp.require(XmlPullParser.START_TAG, null, "dynUI:listPage");
		
		int numAttributes = xpp.getAttributeCount();
		for (int i = 0; i < numAttributes; i++)
		{
			if (xpp.getAttributeName(i).equals("dataObjectName"))
			   this.dataObjectName = xpp.getAttributeValue(i);
		}

	    super.parseTemplate(xpp); // Common XML processing code

	    // Assert Invariant (b)
	    xpp.require(XmlPullParser.END_TAG, null, "dynUI:listPage");
	}

    protected void processTemplateStartElement (XmlPullParser xpp) throws Exception
    {
        String name = xpp.getName();
        String uri = xpp.getNamespace();

        //if ("".equals (uri)) {
        //    System.out.println("Start element: " + name);
        //} else {
        //    System.out.println("Start element: {" + uri + "}" + name);
        //}        

        if (name.equals("dynUI:listPageTitleFormat"))
        {
           String format = xpp.nextText();
           if (format.length() > 0)
              this.listPageTitleFormat = format;         
        }
        else if (name.equals("dynUI:list"))
        {
           DynNaviListUITemplate listObj = new DynNaviListUITemplate(this.selectedPlatform);
           listObj.parseTemplate(xpp);
           if (listObj.dataObjectName == null)
           {
              DynNaviListUITemplate genListObj = sublistTemplates.get("*");
              genListObj.listEntryTemplates.putAll(listObj.listEntryTemplates);
           }
           else
               sublistTemplates.put(listObj.dataObjectName, listObj);
        }
    }



    public void parseData(XmlPullParser xpp, UIModelData currentUIData) throws Exception
    {   
        // Assumes to be at the starting tag 
        // xpp.require(XmlPullParser.START_TAG, null, this.dataObjectName);
        
        super.parseData(xpp, currentUIData); // Common XML processing code
        
        // xpp.require(XmlPullParser.END_TAG, null, this.dataObjectName);
    }    

    protected void processDataStartElement (XmlPullParser xpp, UIModelData currentUIData) throws Exception
    {
        String name = xpp.getName();
        String uri = xpp.getNamespace();

        //if ("".equals (uri)) {
        //    System.out.println("Start element: " + name);
        //} else {
        //    System.out.println("Start element: {" + uri + "}" + name);
        //}

        // Check if current data element is mapped to a List UI widget
        DynNaviListUITemplate sublistUITemplate = sublistTemplates.get(name);
        if (sublistUITemplate == null)
            sublistUITemplate = sublistTemplates.get("*");
       
        // PROBLEM: How to solve for non-existent sublist tags?
        UIModelData sublistUIData = new UIModelData();
        sublistUIData.uiTemplate = sublistUITemplate;
        sublistUITemplate.parseData(xpp, sublistUIData);
        
        // ArrayList<Map> sublistsUI
        // System.out.println("Adding another sublist...");
        currentUIData.childUIElementsData.add(sublistUIData);
    }
    
    // For Main Page generation
    public void generateUI(UIModelData currentUIData)
    {
        // Generate HTML string
        if (this.selectedPlatform == UIEngine.devicePlatform.WEB)
        {
            String UI_htmlcode = "";
            String PageTitle;

            PageTitle = currentUIData.attributesStore.get("_PageTitle"); // Rendering-specified title
            if (PageTitle == null)
            {
                // Template-specified title
                PageTitle = UIModelData.fillStrWithAttr(currentUIData, this.listPageTitleFormat).trim();
            }

            UI_htmlcode += "\t<ul id=\"home\" title=\""+PageTitle+"\" selected=\"true\">";

            // Now for the sublists
            Iterator<UIModelData> childUI_iterator = currentUIData.childUIElementsData.iterator();
            
            while (childUI_iterator.hasNext())
            {
                UIModelData childUI_data = childUI_iterator.next();
                childUI_data.uiTemplate.generateUI(childUI_data);
                if (childUI_data.uiObject != null)
                    UI_htmlcode += ((String)childUI_data.uiObject);
            }

            UI_htmlcode += "\n\t</ul>";
            String filename = "DynNaviListPageUI.html";
            String mainpage_htmlcode;

            try 
            {
            	// Get HTML template code from HTML file residing with java class
                InputStream is = getClass().getResourceAsStream(filename);
                if (is == null)
                   throw new IOException("HTML code for DynNaviListPageUI mainpage not found!!!");
                
                InputStreamReader isr = new InputStreamReader(is);
                BufferedReader br = new BufferedReader(isr);
                StringBuffer sb = new StringBuffer();
                String line;
                while ((line = br.readLine()) != null) 
                {
                  sb.append(line);
                }
                br.close();
                isr.close();
                is.close();
                
                mainpage_htmlcode = sb.toString();
            }
            catch (IOException ioe)
            {   
                mainpage_htmlcode = UI_htmlcode;
                System.out.println("IOException: "+ioe);    
            }
            
            
            // Detect the phrase [[DYNUICODE]] and replace it
            String UI_styling =
    	    "<style type=\"text/css\" media=\"screen\">@import \"iui/iui.css\";</style>  \n" +
    	    "<script type=\"application/x-javascript\" src=\"iui/iui.js\"></script>      \n" +
    	    "<style type=\"text/css\" media=\"screen\">@import \"facade.css\";</style>   \n" + // Comment out to get square-ish styling
    	    "<script type=\"application/x-javascript\" src=\"facade.js\"></script>       \n";  // Comment out to get square-ish styling
            
            mainpage_htmlcode = mainpage_htmlcode.replaceFirst("\\[\\[PAGETITLE\\]\\]", PageTitle);
            mainpage_htmlcode = mainpage_htmlcode.replaceFirst("\\[\\[PAGE_UI_STYLING\\]\\]", UI_styling);
            mainpage_htmlcode = mainpage_htmlcode.replaceFirst("\\[\\[DYNUICODE\\]\\]", UI_htmlcode);

            currentUIData.uiObject = mainpage_htmlcode;
        }
        // else if (this.selectedPlatform == UIEngine.devicePlatform.ANDROID)
        // {
        //    
        // }
    }    

    // For UI fragment to be passed through AJAX
    public void generateUIFragment(UIModelData currentUIData)
    {
        // Generate HTML string
        if (this.selectedPlatform == UIEngine.devicePlatform.WEB)
        {
            String UI_htmlcode = "";
            // String pageTitle = UIModelData.fillStrWithAttr(currentUIData, this.listPageTitleFormat).trim();
            String pageTitle = currentUIData.attributesStore.get("_PageTitle");
            String pageTitleURLEncoded;

            // System.out.println("Start: "+(new Date().getTime()/1000));
            
            if (pageTitle == null) pageTitle = "";
            try {
                pageTitleURLEncoded = URLEncoder.encode(pageTitle, "UTF-8");
            } 
            catch(UnsupportedEncodingException e) { 
                pageTitleURLEncoded = "";
            }

            UI_htmlcode += "\t<ul id=\""+pageTitleURLEncoded+"\" title=\""+pageTitle+"\">";

            // Now for the sublists
            Iterator<UIModelData> childUI_iterator = currentUIData.childUIElementsData.iterator();
            while (childUI_iterator.hasNext())
            {
                UIModelData childUI_data = childUI_iterator.next();
                childUI_data.uiTemplate.generateUI(childUI_data);
                if (childUI_data.uiObject != null)
                    UI_htmlcode += ((String)childUI_data.uiObject);
            }

            UI_htmlcode += "\n\t</ul>";          
            currentUIData.uiObject = UI_htmlcode;
            // System.out.println("End: "+(new Date().getTime()/1000));
        }
        // else if (this.selectedPlatform == UIEngine.devicePlatform.ANDROID)
        // {
        //    
        // }   
    }
    
    
    private static String readFileAsString(String filePath) throws java.io.IOException
    {
        StringBuilder fileData = new StringBuilder(1000);
        BufferedReader reader = new BufferedReader(new FileReader(filePath));
        char[] buf = new char[1024];
        int numRead=0;
        while((numRead=reader.read(buf)) != -1)
        {
            fileData.append(buf, 0, numRead);
        }
        reader.close();
        return fileData.toString();
    }    





	/* Internal Classes */

	private class DynNaviListUITemplate extends UITemplate
	{
		private String listTitleFormat = null;
		private Map<String,DynNaviListEntryUITemplate> listEntryTemplates
		= new HashMap<String,DynNaviListEntryUITemplate>();
		
		DynNaviListUITemplate(devicePlatform dP)
		{   super("dynUI:list", dP);   }

        DynNaviListUITemplate(String objNameMapping, devicePlatform dP)
        {     
            super("dynUI:list", dP);
            this.dataObjectName = objNameMapping;
        }		
		
		public void parseTemplate(XmlPullParser xpp) throws Exception
		{
	        // Expects to be at the starting tag 
	        // <dynUI:list ...>	        
	        xpp.require(XmlPullParser.START_TAG, null, "dynUI:list");

	        int numAttributes = xpp.getAttributeCount();
	        for (int i = 0; i < numAttributes; i++)
	        {
	            if (xpp.getAttributeName(i).equals("dataObjectName"))
	               this.dataObjectName = xpp.getAttributeValue(i);
	        }

	        super.parseTemplate(xpp);
	        xpp.require(XmlPullParser.END_TAG, null, "dynUI:list");   
		}
		
        protected void processTemplateStartElement (XmlPullParser xpp) throws Exception
        {
            String name = xpp.getName();
            String uri = xpp.getNamespace();

            //if ("".equals (uri)) {
            //    System.out.println("Start element: " + name);
            //} else {
            //    System.out.println("Start element: {" + uri + "}" + name);
            //}        

            if (name.equals("dynUI:listTitleFormat"))
            {
               String format = xpp.nextText();
               if (format.length() > 0)
                  this.listTitleFormat = format;
            }
            else if (name.equals("dynUI:listEntry"))
            {
               DynNaviListEntryUITemplate listEntryObj = new DynNaviListEntryUITemplate(this.selectedPlatform);
               listEntryObj.parseTemplate(xpp);
               if (listEntryObj.dataObjectName != null)
               {
                  listEntryTemplates.put(listEntryObj.dataObjectName, listEntryObj);
               }
            }
        }



        public void parseData(XmlPullParser xpp, UIModelData currentUIData) throws Exception
        {   
            // Assumes to be at the starting tag 
            // xpp.require(XmlPullParser.START_TAG, null, this.dataObjectName);           
                        
            super.parseData(xpp, currentUIData); // Common XML processing code

            // xpp.require(XmlPullParser.END_TAG, null, this.dataObjectName);
        }    

        protected void processDataStartElement (XmlPullParser xpp, UIModelData currentUIData) throws Exception
        {
            String name = xpp.getName();
            String uri = xpp.getNamespace();

            //if ("".equals (uri)) {
            //    System.out.println("Start element: " + name);
            //} else {
            //    System.out.println("Start element: {" + uri + "}" + name);
            //}

            // Check if current data element is mapped to a ListEntry UI widget
            DynNaviListEntryUITemplate listEntryUITemplate = listEntryTemplates.get(name);
            if (listEntryUITemplate == null)
            {
                // Process as additional attributes for current List UI widget
                if (!this.dataObjectName.equals("*"))
                {
                    String value;
                    try {
                        value = xpp.nextText();
                    } catch(XmlPullParserException e) {
                        return;
                    }
                    currentUIData.attributesStore.put(name, value);
                }
            }
            else
            {
                UIModelData listEntryUIData = new UIModelData();
                listEntryUIData.uiTemplate = listEntryUITemplate;
                listEntryUITemplate.parseData(xpp, listEntryUIData);
                
                // ArrayList<Map> listEntriesUI
                currentUIData.childUIElementsData.add(listEntryUIData);
            }
        }

        public void generateUI(UIModelData currentUIData)
        {
            Boolean showSublistHeader = true;
            
            // Should not show a sublist header UI widget
            if (this.dataObjectName == null || this.listTitleFormat == null)
                showSublistHeader = false;
            
            // Generate HTML string
            if (this.selectedPlatform == UIEngine.devicePlatform.WEB)
            {
                String UI_htmlcode = "";
                
                if (showSublistHeader) 
                {
                    UI_htmlcode += "\n\t\t<li class=\"group\">";
                    UI_htmlcode += UIModelData.fillStrWithAttr(currentUIData, this.listTitleFormat).trim();
                    UI_htmlcode += "</li>";
                }

                // Now for the entries in the sublist
                Iterator<UIModelData> childUI_iterator = currentUIData.childUIElementsData.iterator();
                
                while (childUI_iterator.hasNext())
                {
                    UIModelData childUI_data = childUI_iterator.next();
                    childUI_data.uiTemplate.generateUI(childUI_data);
                    if (childUI_data.uiObject != null)
                        UI_htmlcode += "\n\t\t"+((String)childUI_data.uiObject);
                }
                
                currentUIData.uiObject = UI_htmlcode;
            }
            // else if (this.selectedPlatform == UIEngine.devicePlatform.ANDROID)
            // {
            //    
            // }
        }

	}



	private enum listEntryActions 
	{ NONE, SHOW_NEWLISTPAGE, EXPAND_SUBLIST, SHOW_CUSTOMPAGE, EXTERNAL_LINK }
	private enum listEntryActionCallTypes 
	{ NONE, WEB, ANDROID_INTENTION, IPHONE_PROCESS }
	
	private class DynNaviListEntryUITemplate extends UITemplate
	{
	    private String listEntryFormat = null;
	    private String listEntryImage = null;
	    private listEntryActions listEntryAction = listEntryActions.NONE;
	    private String listEntryActionCall = null;
	    private String listEntryNewPageTitle = null;
	    private listEntryActionCallTypes listEntryActionCallType = listEntryActionCallTypes.NONE;

		DynNaviListEntryUITemplate(devicePlatform dP)
		{
		    super("dynUI:listEntry", dP);
		}
		
		public void parseTemplate(XmlPullParser xpp) throws Exception
		{
            // Expects to be at the starting tag 
            // <dynUI:listEntry ...>         
            xpp.require(XmlPullParser.START_TAG, null, "dynUI:listEntry");

            int numAttributes = xpp.getAttributeCount();
            for (int i = 0; i < numAttributes; i++)
            {
                if (xpp.getAttributeName(i).equals("dataObjectName"))
                   this.dataObjectName = xpp.getAttributeValue(i);
            }

            super.parseTemplate(xpp);
            xpp.require(XmlPullParser.END_TAG, null, "dynUI:listEntry");
            
		}
		
	    protected void processTemplateStartElement (XmlPullParser xpp) throws Exception
	    {
            String name = xpp.getName();
            String uri = xpp.getNamespace();

            //if ("".equals (uri)) {
            //    System.out.println("Start element: " + name);
            //} else {
            //    System.out.println("Start element: {" + uri + "}" + name);
            //}        

            if (name.equals("dynUI:listEntryFormat"))
            {
               String format = xpp.nextText();
               if (format.length() > 0)
                  this.listEntryFormat = format;
            }
            else if (name.equals("dynUI:listEntryImage"))
            {
               String format = xpp.nextText();
               if (format.length() > 0)
                  this.listEntryImage = format;
            }
            else if (name.equals("dynUI:listEntryAction"))
            {
               String action = xpp.nextText();
               if (action.equals("showNewListPage"))
                  this.listEntryAction = listEntryActions.SHOW_NEWLISTPAGE;
               else if (action.equals("expandSublist"))
                  this.listEntryAction = listEntryActions.EXPAND_SUBLIST;
               else if (action.equals("showCustomPage"))
                  this.listEntryAction = listEntryActions.SHOW_CUSTOMPAGE;
               else if (action.equals("externalLink"))
                  this.listEntryAction = listEntryActions.EXTERNAL_LINK;
            }
            else if (name.equals("dynUI:listEntryNewPageTitle"))
            {
               String newpageTitle = xpp.nextText();
               if (newpageTitle.length() > 0)
                  this.listEntryNewPageTitle = newpageTitle;
            }            
            else if (name.equals("dynUI:listEntryActionCall"))
            {
               String actionCall = xpp.nextText();
               if (actionCall.length() > 0)
                  this.listEntryActionCall = actionCall;
               
               int numAttributes = xpp.getAttributeCount();
               for (int i = 0; i < numAttributes; i++)
               {
                   if (xpp.getAttributeName(i).equals("callType"))
                   {
                      String callType = xpp.getAttributeValue(i);
                      
                      if (callType.equals("web"))
                         this.listEntryActionCallType = listEntryActionCallTypes.WEB;
                       else if (callType.equals("androidIntention"))
                         this.listEntryActionCallType = listEntryActionCallTypes.ANDROID_INTENTION;
                       else if (callType.equals("iPhoneProcess"))
                         this.listEntryActionCallType = listEntryActionCallTypes.IPHONE_PROCESS;
                   }
               }
            }
	    
	    }



        // UI
        // attributesStore: a HashMap of attribute values - Containing text-only        
        public void parseData(XmlPullParser xpp, UIModelData currentUIData) throws Exception
        {   
            // Assumes to be at the starting tag 
            // xpp.require(XmlPullParser.START_TAG, null, this.dataObjectName);

            // Attributes from <xmltag attr="..."
            
            super.parseData(xpp, currentUIData); // Common XML processing code

            // xpp.require(XmlPullParser.END_TAG, null, this.dataObjectName);
        }

        protected void processDataStartElement (XmlPullParser xpp, UIModelData currentUIData) throws Exception
        {
            String name = xpp.getName();
            String uri = xpp.getNamespace();

            //if ("".equals (uri)) {
            //    System.out.println("Start element: " + name);
            //} else {
            //    System.out.println("Start element: {" + uri + "}" + name);
            //}

            // Treat xml elements value as attributes data 
            try 
            {
            	String value = null;
                value = xpp.nextText();
                if (value != null && value.trim().length() > 0)
                   currentUIData.attributesStore.put(name, value);
            } 
            catch(XmlPullParserException e) 
            {
                return;
            }

        }	
        
        public void generateUI(UIModelData currentUIData)
        {
            // Hide this UI list entry widget
            if (this.listEntryFormat == null)
                return;
            
            // Generate HTML string
            if (this.selectedPlatform == UIEngine.devicePlatform.WEB)
            {
                String UI_htmlcode = "<li>";
                String listEntryText 
                = UIModelData.fillStrWithAttr(currentUIData, this.listEntryFormat).trim();

                
                if (this.listEntryAction == listEntryActions.SHOW_NEWLISTPAGE)
                {                   
                    String pageTitle = "", actionCall = "";
                         
                    try {
                        if (this.listEntryNewPageTitle != null) {
                            pageTitle = UIModelData.fillStrWithAttr(currentUIData, this.listEntryNewPageTitle).trim();
                            pageTitle = URLEncoder.encode(pageTitle, "UTF-8");
                        }
                        if (this.listEntryActionCall != null){
                            actionCall = UIModelData.fillStrWithAttr(currentUIData, this.listEntryActionCall).trim();
                            actionCall = URLEncoder.encode(actionCall, "UTF-8");
                        }
                    } 
                    catch(UnsupportedEncodingException e)
                    { }

                    // Whether a thumbnail should be displayed for this list-entry
                    if (this.listEntryImage != null)
                    {
                        String picAddr = UIModelData.fillStrWithAttr(currentUIData, this.listEntryImage).trim();
                        // If XML does not specify a thumbnail, don't show anything
                        if (!picAddr.equals(this.listEntryImage))
                        	listEntryText = "<img style=\"border: medium none; vertical-align: middle; \" height=60px width=60px src=\""+picAddr+"\"/>"
                                            + "<span style=\"padding-left: 25px;\">"+listEntryText+"</span>";
                        else
                        	listEntryText 
                            = "<div style=\"padding-left: 10px; padding-top: 12px;\">"+listEntryText+"</div>";
                    }
                    else
                    	listEntryText 
                        = "<div style=\"padding-left: 10px; padding-top: 12px;\">"+listEntryText+"</div>";
                    

                    if (this.listEntryActionCall != null)
                    {
                        UI_htmlcode += "<a href=\"processor.jsp?pageTitle="+pageTitle+"&actionCall="+actionCall+"\">"+listEntryText+"</a></li>";
                    }
                    else
                        UI_htmlcode += listEntryText+"</li>";
                }
                else if (this.listEntryAction == listEntryActions.EXTERNAL_LINK)
                {
                    UI_htmlcode += "<a href=\""+this.listEntryActionCall+"\" target=\"_self\">"+listEntryText+"</a></li>";
                }
                // else if (this.listEntryAction == listEntryActions.SHOW_CUSTOMPAGE)
                // {
                //     
                // }
                
                currentUIData.uiObject = UI_htmlcode;
            }
            // else if (this.selectedPlatform == UIEngine.devicePlatform.ANDROID)
            // {
            //    
            // }
        }
         
	}

	
}